package ru.spb.osll.myfit.server.execute;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

import org.apache.log4j.Logger;

public class FitNesseTestRunnerProxy extends FitNesseTestRunner {
  private Logger log = Logger.getLogger(FitNesseTestRunnerProxy.class);
  private Object m_testRunner;
  private ClassLoader m_classLoader;
  	
  public FitNesseTestRunnerProxy(String rootPath, String rootDirectoryName, ClassLoader classLoader, ProgressFixtureListener listener) throws Exception {
    m_classLoader = classLoader;
    
    try {
      m_testRunner = createTestRunner(rootPath, rootDirectoryName, listener);
    } catch(Exception e) {
      log.error("Error creating test runner", e);
      throw e;
    }
  }
  
  @Override
  public void run(String pagePath) throws Exception {
	  Method method = m_testRunner.getClass().getMethod("run", String.class);
	  method.invoke(m_testRunner, pagePath);
  }
  
  private Object createTestRunner(String rootPath, String rootDirectoryName, ProgressFixtureListener listener) throws Exception {
	  Class<MyFitFixtureLoader> fixtureLoaderClass = clazz(MyFitFixtureLoader.class);
	  Constructor<MyFitFixtureLoader> fixtureLoaderConstructor = fixtureLoaderClass.getConstructor(ClassLoader.class);
	  Object fixtureLoader = fixtureLoaderConstructor.newInstance(m_classLoader);
	  
	  Class<ProgressFixtureListenerProxy> listenerProxyClass = clazz(ProgressFixtureListenerProxy.class);
	  Constructor<ProgressFixtureListenerProxy> listenerProxyConstructor = listenerProxyClass.getConstructor(ClassLoader.class, Object.class);
	  Object listenerProxy = listenerProxyConstructor.newInstance(getClass().getClassLoader(), listener);
	   
	  Class<MyFitFixtureRunner> fixtureRunnerClass = clazz(MyFitFixtureRunner.class);
	  Constructor<MyFitFixtureRunner> fixtureRunnerConstructor = fixtureRunnerClass.getConstructor(fixtureLoaderClass, clazz(ProgressFixtureListener.class));
	  Object fixtureRunner = fixtureRunnerConstructor.newInstance(fixtureLoader, listenerProxy);
	  
	  Class<FitNesseTestRunner> clazz = clazz(FitNesseTestRunner.class);
	  Constructor<FitNesseTestRunner> constructor = clazz.getConstructor(String.class, String.class, fixtureLoaderClass, fixtureRunnerClass);
	  return constructor.newInstance(rootPath, rootDirectoryName, fixtureLoader, fixtureRunner);
  }
  
  @SuppressWarnings("unchecked")
  private <T> Class<T> clazz(Class<T> clazz) throws ClassNotFoundException {
	  return (Class<T>) m_classLoader.loadClass(clazz.getName());
  }

}
